package com.ym521.logdog.engine

import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import com.ym521.logdog.core.IDiskLogEngine
import com.ym521.logdog.core.LogDogConfig
import com.ym521.logdog.core.LogPriority
import com.ym521.logdog.utils.AESecurityUtil
import com.ym521.logdog.utils.CacheUtil
import com.ym521.logdog.utils.DateUtil
import com.ym521.logdog.utils.StringCodeUtil
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

/**
 * @author YM
 * @E-mail 2435970206@qq
 * @QQ 2435970206
 * 日志文件写入实现
 * 通过实现使用APP 私有空间 减少对用户的权限索取
 */
internal class DiskLogEngine(looper: Looper) : Handler(looper),
    IDiskLogEngine {
    private val TAG = DiskLogEngine::class.simpleName

    //普通Log文件对象
    private var logFile: File? = null

    //普通Log当前日期
    private var currentLogDate: String? = null

    companion object {
        private val engine: DiskLogEngine? = null
        @Synchronized
        fun create(looper: Looper): IDiskLogEngine {
            return engine ?: DiskLogEngine(looper)
        }
    }

    /**
     * 对外提供写入信息的接口
     */
    override fun logWrite(priority: LogPriority, tag: String, msg: String) {
        val msgContent =
            if (LogDogConfig.isLogFileAES && LogDogConfig.logFileAES_key.isNotBlank()) {
                val keyBytes = LogDogConfig.logFileAES_key.toByteArray(Charsets.UTF_8)
                AESecurityUtil.encrypt(msg, keyBytes)
            } else {
                msg
            }
        val dateTiem = DateUtil.currentDateMessage()
        val message = this.obtainMessage()
        message.obj = when (priority) {
            LogPriority.DEBUG -> "DEBUG    $dateTiem    $tag    $msgContent \n"
            LogPriority.INFO -> "INFO    $dateTiem    $tag    $msgContent \n"
            LogPriority.WARN -> "WARN     $dateTiem    $tag    $msgContent \n"
            LogPriority.ERROR -> "ERROR    $dateTiem    $tag    $msgContent \n"
            LogPriority.CRASH -> "CRASH    $dateTiem    $tag    $msgContent \n"
        }
        this.sendMessage(message)
    }

    /**
     * 接收Message
     */
    override fun handleMessage(msg: Message) {
        val logMessage = msg.obj as String
        writeLogFile(logMessage)
    }


    /**
     *写入 Log日志文件
     */
    private fun writeLogFile(logMsg: String) {
        logFileCut()
        logFile?.let {
            var buff: BufferedOutputStream? = null
            try {
                if (!it.exists()) {
                    it.parentFile?.mkdirs()
                    it.createNewFile()
                }
                buff = BufferedOutputStream(FileOutputStream(it, true))
                if (LogDogConfig.encoding) {
                    buff.write(StringCodeUtil.encryptionString(logMsg))
                } else {
                    buff.write(logMsg.toByteArray(Charsets.UTF_8))
                }
            } catch (e: IOException) {
                Log.e(TAG, e.toString())
            } finally {
                buff?.flush()
                buff?.close()
            }
        }
    }

    private fun logFileCut() {
        val currentDate = DateUtil.currentDateFile()
        //判断是否存在缓存
        if (this.currentLogDate == null) {
            val cacheArray = CacheUtil.getCurrentLogInfo()
            if (cacheArray.isNotEmpty() && cacheArray[0] == currentDate) {
                this.currentLogDate = cacheArray[0]
                this.logFile = File(cacheArray[1])
            }
        }
        //判断是否日期是否发生变更
        if (currentDate != this.currentLogDate) {
            val fileName = "${currentDate}.log"
            val logFile = File(DiskLogEngineFactory.ROOT_DIR, fileName)
            CacheUtil.saveCurrentLogInfo(currentDate, logFile.absolutePath)
            this.logFile = logFile
            this.currentLogDate = currentDate
        }

        //日志文件分割
        logFile?.let {
            if (!it.isFile) return
            if (it.length() > 1024 * 1024 * LogDogConfig.logFileSize) {
                var logFileSum = 0
                while (true) {
                    logFileSum++
                    val fileName = "${currentDate}_$logFileSum.log"
                    val logFile = File(DiskLogEngineFactory.ROOT_DIR, fileName)
                    if (!logFile.exists()) {
                        this.logFile = logFile
                        CacheUtil.saveCurrentLogInfo(currentDate, logFile.absolutePath)
                        break
                    } else {
                        if (it.length() < 1024 * LogDogConfig.logFileSize)
                            break
                    }
                }
            }
        }
    }

}